package com.pureut.equipment.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pureut.common.core.exception.GlobalException;
import com.pureut.common.datascope.annotation.DataScope;
import com.pureut.common.security.utils.DictUtils;
import com.pureut.common.security.utils.SecurityUtils;
import com.pureut.equipment.domain.*;
import com.pureut.equipment.domain.dto.DeviceRecordDto;
import com.pureut.equipment.domain.dto.PatrolItemPlanDto;
import com.pureut.equipment.domain.dto.PlannedAllocationDto;
import com.pureut.equipment.domain.vo.PatrolItemPlanVo;
import com.pureut.equipment.domain.vo.PatrolWorkOrderVo;
import com.pureut.equipment.domain.vo.ReturnDeviceStatusVo;
import com.pureut.equipment.mapper.DeviceRecordMapper;
import com.pureut.equipment.mapper.PatrolItemMapper;
import com.pureut.equipment.mapper.PatrolItemPlanMapper;
import com.pureut.equipment.mapper.PlannedAllocationMapper;
import com.pureut.equipment.service.DeviceRecordService;
import com.pureut.equipment.service.PatrolItemPlanService;
import com.pureut.equipment.service.PatrolWorkOrderService;
import com.pureut.equipment.service.PlannedAllocationService;
import com.pureut.system.api.FeignService;
import com.pureut.system.api.domain.SysDictData;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/***
 *
 * Author:巡检计划实现层
 * Date:2023/04/26 10:43
 * @DESC
 */
@Service
public class PatrolItemPlanServiceImpl extends ServiceImpl<PatrolItemPlanMapper, PatrolItemPlan> implements PatrolItemPlanService {

    /**
     * 巡检计划mapper
     */
    @Resource
    PatrolItemPlanMapper patrolItemPlanMapper;

    /**
     * 基础模块fegin
     */
    @Resource
    FeignService feignService;

    /**
     * 配置计划service
     */
    @Resource
    PlannedAllocationService plannedAllocationService;

    /**
     * 配置计划mapper
     */
    @Resource
    PlannedAllocationMapper plannedAllocationMapper;

    /**
     * 巡检项目mapper
     */
    @Resource
    PatrolItemMapper patrolItemMapper;

    /**
     * 设备mapper
     */
    @Resource
    DeviceRecordMapper deviceRecordMapper;

    /**
     * 设备fegin
     */
    @Resource
    DeviceRecordService deviceRecordService;

    /**
     * 巡检工单service
     */
    @Resource
    PatrolWorkOrderService patrolWorkOrderService;


    /**
     * 巡检计划列表
     *
     * @param patrolItemPlanVo
     * @return
     */
    @Override
    @DataScope(deptAlias = "a")
    public List<PatrolItemPlanDto> getList(PatrolItemPlanVo patrolItemPlanVo) {
        List<SysDictData> planTypeArray = DictUtils.getDictCache("planned_allocation_plan_type");
        Map<String, String> planTypeMap = planTypeArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        List<PatrolItemPlanDto> dataList = patrolItemPlanMapper.getDataList(patrolItemPlanVo);
        for (PatrolItemPlanDto entity : dataList) {
            entity.setPlanTypeDict(planTypeMap.get(entity.getPlanType()));
        }
        return dataList;
    }

    /**
     * 新增
     *
     * @param patrolItemPlanVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(PatrolItemPlanVo patrolItemPlanVo) throws Exception {
        //保存采购计划数据
        PatrolItemPlan patrolItemPlan = new PatrolItemPlan();
        String authorityCoding = feignService.getAuthorityCoding("device:inspection:plan:list");
        if (authorityCoding == null) {
            throw new GlobalException("该单据未进行配置，无法生成单据编码");
        }
        patrolItemPlan.setPatrolItemPlanCode(authorityCoding)
                .setStatus(2)
                .setPlanName(patrolItemPlanVo.getPlanName())
                .setPlanStartTime(patrolItemPlanVo.getPlanStartTime())
                .setPlanEndTime(patrolItemPlanVo.getPlanEndTime())
                .setPatrolItemIdStr(patrolItemPlanVo.getPatrolItemIdStr())
                .setEquipmentIdStr(patrolItemPlanVo.getEquipmentIdStr())
                .setCreateTime(new Date())
                .setCreateBy(SecurityUtils.getUsername())
                .setDeptId(SecurityUtils.getDeptId());
        boolean isBoolean = save(patrolItemPlan);
        if (isBoolean) {
            //保存采购计划对应的计划配置项数据
            PlannedAllocation plannedAllocationData = patrolItemPlanVo.getPlannedAllocation();

            PlannedAllocation plannedAllocation = new PlannedAllocation();
            plannedAllocation.setAllocationType(3)
                    .setExecutionInterval(plannedAllocationData.getExecutionInterval())
                    .setExecutionCycle(plannedAllocationData.getExecutionCycle())
                    .setExecutionMonth(plannedAllocationData.getExecutionMonth())
                    .setExecutionDays(plannedAllocationData.getExecutionDays())
                    .setPlanId(patrolItemPlan.getId())
                    .setPlanType(plannedAllocationData.getPlanType());
            plannedAllocationService.save(plannedAllocation);
            //将计划id回传
            PatrolItemPlan byId = getById(patrolItemPlan.getId());
            byId.setPlannedAllocationId(plannedAllocation.getId());
            updateById(byId);
            //回传设备状态
            ReturnDeviceStatusVo returnDeviceStatusVo = new ReturnDeviceStatusVo();
            returnDeviceStatusVo.setDeviceIds(patrolItemPlanVo.getEquipmentIdStr());
            returnDeviceStatusVo.setStatus(5);
            deviceRecordService.returnDeviceStatus(returnDeviceStatusVo);
        }
        return isBoolean;
    }

    /**
     * 删除
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deletePatrolItemPlan(Long id) {
        PatrolItemPlan byId = getById(id);
        if (byId.getStatus() != 1) {
            //将计划配置数据删除
            PlannedAllocation plannedAllocation = plannedAllocationMapper.selectOne(new QueryWrapper<PlannedAllocation>().lambda().eq(PlannedAllocation::getPlanId, id).eq(PlannedAllocation::getAllocationType, 3));
            boolean b = plannedAllocationService.removeById(plannedAllocation);
            if (b) {
                //删除保养计划
                removeById(byId);
            }
            return b;
        } else {
            throw new GlobalException("计划启用中，无法删除");
        }
    }

    /**
     * 修改
     *
     * @param patrolItemPlanVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updatePatrolItemPlan(PatrolItemPlanVo patrolItemPlanVo) {
        PatrolItemPlan patrolItemPlan = getById(patrolItemPlanVo.getId());
        if (patrolItemPlan.getStatus() == 2) {
            patrolItemPlan.setPlanName(patrolItemPlanVo.getPlanName())
                    .setPlanStartTime(patrolItemPlanVo.getPlanStartTime())
                    .setPlanEndTime(patrolItemPlanVo.getPlanEndTime())
                    .setPatrolItemIdStr(patrolItemPlanVo.getPatrolItemIdStr())
                    .setEquipmentIdStr(patrolItemPlanVo.getEquipmentIdStr());
            boolean b = updateById(patrolItemPlan);
            if (b) {
                //获取对应的计划配置数据
                PlannedAllocation plannedAllocation = plannedAllocationMapper.selectOne(new QueryWrapper<PlannedAllocation>().lambda().eq(PlannedAllocation::getPlanId, patrolItemPlan.getId()).eq(PlannedAllocation::getAllocationType, 3));
                PlannedAllocation plannedAllocationData = patrolItemPlanVo.getPlannedAllocation();
                plannedAllocation
                        .setPlanType(plannedAllocationData.getPlanType())
                        .setExecutionInterval(plannedAllocationData.getExecutionInterval())
                        .setExecutionCycle(plannedAllocationData.getExecutionCycle())
                        .setExecutionMonth(plannedAllocationData.getExecutionMonth())
                        .setExecutionDays(plannedAllocationData.getExecutionDays())
                        .setPlanType(plannedAllocationData.getPlanType());
                plannedAllocationService.updateById(plannedAllocation);
            }
            return b;
        } else {
            throw new GlobalException("只能修改待启用的数据");
        }
    }

    /**
     * 查看
     *
     * @param id
     * @return
     */
    @Override
    public PatrolItemPlanDto getView(Long id) {
        PatrolItemPlanDto patrolItemPlanDto = new PatrolItemPlanDto();
        //获取计划单数据
        PatrolItemPlan patrolItemPlan = getById(id);
        //获取对应的计划配置数据
        PlannedAllocation plannedAllocation = plannedAllocationMapper.selectOne(new QueryWrapper<PlannedAllocation>().lambda().eq(PlannedAllocation::getPlanId, patrolItemPlan.getId()).eq(PlannedAllocation::getAllocationType, 3));

        //获取巡检项目
        List<String> patrolItemIds = Arrays.asList(patrolItemPlan.getPatrolItemIdStr().split(","));
        List<PatrolItem> patrolItems = patrolItemMapper.selectList(new QueryWrapper<PatrolItem>().lambda().in(PatrolItem::getId, patrolItemIds));
        patrolItemPlanDto.setPatrolItems(patrolItems);
        //获取关联设备
        List<String> equipmentIds = Arrays.asList(patrolItemPlan.getEquipmentIdStr().split(","));
        List<DeviceRecordDto> drvices = deviceRecordMapper.getDeviceByIds(equipmentIds);
        patrolItemPlanDto.setDrvices(drvices);
        //封装计划配置项
        PlannedAllocationDto plannedAllocationDto = new PlannedAllocationDto();
        //执行周期列表
        List<String> cycleList = Arrays.asList(plannedAllocation.getExecutionCycle().split(","));
        //执行月份列表
        List<String> monthList = Arrays.asList(plannedAllocation.getExecutionMonth().split(","));
        //执行日期列表
        List<String> daysList = Arrays.asList(plannedAllocation.getExecutionDays().split(","));

        plannedAllocationDto.setId(plannedAllocation.getId())
                .setPlanId(plannedAllocation.getPlanId())
                .setPlanType(plannedAllocation.getPlanType())
                .setExecutionInterval(plannedAllocation.getExecutionInterval())
                .setExecutionCycleList(cycleList)
                .setExecutionMonthList(monthList)
                .setExecutionDaysList(daysList);
        patrolItemPlanDto.setId(patrolItemPlan.getId());
        patrolItemPlanDto.setPlannedAllocationDto(plannedAllocationDto);
        patrolItemPlanDto.setPatrolItemPlanCode(patrolItemPlan.getPatrolItemPlanCode());
        patrolItemPlanDto.setPlanName(patrolItemPlan.getPlanName());
        patrolItemPlanDto.setPlanStartTime(patrolItemPlan.getPlanStartTime());
        patrolItemPlanDto.setPlanEndTime(patrolItemPlan.getPlanEndTime());

        return patrolItemPlanDto;
    }

    /**
     * 启用
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean enable(Long id) throws Exception {
        PatrolItemPlan patrolItemPlan = getById(id);
        long timeStart = patrolItemPlan.getPlanStartTime().getTime();
        long timeEnd = patrolItemPlan.getPlanEndTime().getTime();
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date nowParse = simpleDateFormat.parse(simpleDateFormat.format(date));
        long timeNow = nowParse.getTime();
        if (timeNow < timeStart || timeNow > timeEnd) {
            patrolItemPlan.setStatus(4);
            return updateById(patrolItemPlan);
        }
        if (patrolItemPlan.getStatus() == 3 || patrolItemPlan.getStatus() == 2) {
            patrolItemPlan.setStatus(1);
            PlannedAllocation plannedAllocation = plannedAllocationMapper.selectOne(new QueryWrapper<PlannedAllocation>().lambda().eq(PlannedAllocation::getId, patrolItemPlan.getPlannedAllocationId()).eq(PlannedAllocation::getAllocationType, 3));
            // 若计划类型为”日”时，则在启用时立即执行一次；
            if (plannedAllocation.getPlanType() == 1) {
                if (patrolItemPlan.getStatus() != 3) {
                    if (timeNow >= timeStart && timeNow <= timeEnd) {
                        //生成保养工单
                        PatrolWorkOrderVo patrolWorkOrderVo = new PatrolWorkOrderVo();
                        patrolWorkOrderVo.setPatrolItemIdStr(patrolItemPlan.getPatrolItemIdStr());
                        patrolWorkOrderVo.setDeviceIds(patrolItemPlan.getEquipmentIdStr());
                        patrolWorkOrderVo.setSubordinatePlan(patrolItemPlan.getId());
                        patrolWorkOrderService.addToday(patrolWorkOrderVo);
                    }
                }
            }
            return updateById(patrolItemPlan);
        } else {
            throw new GlobalException("只能启用状态为”已停用”的计划");
        }
    }

    /**
     * 停用
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean stop(Long id) {
        PatrolItemPlan patrolItemPlan = getById(id);
        if (patrolItemPlan.getStatus() == 1) {
            patrolItemPlan.setStatus(3);
            return updateById(patrolItemPlan);
        } else {
            throw new GlobalException("只能停用状态为”启用中”的计划");
        }
    }

    /**
     * 根据巡检计划开始时间和结束时间定时修改计划状态(定时任务调用)
     */
    @Override
    public boolean updatePatrolStatusByTime() throws ParseException {
        List<PatrolItemPlan> list = list();
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date nowParse = simpleDateFormat.parse(simpleDateFormat.format(date));
        long nowTime = nowParse.getTime();
        for (PatrolItemPlan entity : list) {
            long planEndTime = entity.getPlanEndTime().getTime();
            long planStartTime = entity.getPlanStartTime().getTime();
            if (nowTime < planStartTime || nowTime > planEndTime) {
                entity.setStatus(4);
            }
        }
        return updateBatchById(list);
    }
}
